/*
 * libExtended2.c
 *
 *  Created on: 16/04/2012
 *      Author: utnso
 */

#include "libExtended2.h"

static staticGroupDescriptor_t* staticGroupDescriptorTable = NULL;
static staticSuperBlock_t staticSuperBlock = { 0 };
static pthread_rwlock_t rwlockSuperBlock = PTHREAD_RWLOCK_INITIALIZER;

int8_t inicializarFileSystem() {
	leerSuperBlock();
	leerGroupDescriptorTable();
	return 0;
}
//--------------------------------------------------
//LECTURA Y ESCRITURA DE BLOQUES
//--------------------------------------------------

char* leerBloqueLocal(uint64_t numBlockGroup, uint64_t numBlock) {
	uint64_t numBloqueGlobal = deBloqueLocalAGlobal(numBlockGroup, numBlock);
	return leerBloqueGlobal(numBloqueGlobal);
}

char* leerBloqueGlobal(uint64_t numBlock) {
	//printf("Tengo que leer el bloque [%d].\n", (uint32_t) numBlock);
	char* contenido;
	contenido = leerBytes((off_t) numBlock * staticSuperBlock.blockSize, (size_t) staticSuperBlock.blockSize);
	//printf("Su contenido es:\n");
	//uint16_t i;
	//for(i = 0; i < staticSuperBlock.blockSize; i++){
		//printf("Byte:[%d] -- Contenido:[%d]:[%c]\n", i, contenido[i], contenido[i]);
	//}
	return contenido;
}

char* leerParteBloqueLocal(uint64_t numBlockGroup, uint64_t numBlock, uint64_t byteInicio, uint64_t byteFin) {
	uint64_t numBloqueGlobal = deBloqueLocalAGlobal(numBlockGroup, numBlock);
	return leerParteBloqueGlobal(numBloqueGlobal, byteInicio, byteFin);
}

char* leerParteBloqueGlobal(uint64_t numBloque, uint64_t byteInicio, uint64_t byteFin) {
	char* contenidoAux = leerBloqueGlobal(numBloque);
	char* contenido = (char*) malloc(byteFin - byteInicio + 1);
	memcpy(contenido, contenidoAux + byteInicio, byteFin - byteInicio + 1);
	free(contenidoAux);
	return contenido;
}

uint8_t escribirBloqueLocal(uint64_t numBlockGroup, uint64_t numBlock, char* contenido) {
	uint64_t numBloqueGlobal = deBloqueLocalAGlobal(numBlockGroup, numBlock);
	return escribirBloqueGlobal(numBloqueGlobal, contenido);
}

uint8_t escribirBloqueGlobal(uint64_t numBlock, char* contenido) {
	uint32_t blockSize = staticSuperBlock.blockSize;
	escribirBytes((off_t) numBlock * blockSize, (size_t) blockSize, contenido);
	return 0;
}

uint8_t escribirParteBloqueLocal(uint64_t numBlockGroup, uint64_t numBlock, uint64_t byteInicio, uint64_t byteFin, char* contenido) {
	uint64_t numBloqueGlobal = deBloqueLocalAGlobal(numBlockGroup, numBlock);
	return escribirParteBloqueGlobal(numBloqueGlobal, byteInicio, byteFin, contenido);
}

uint8_t escribirParteBloqueGlobal(uint64_t numBloque, uint64_t byteInicio, uint64_t byteFin, char* contenido) {
	char* contenidoAux = leerBloqueGlobal(numBloque);
	memcpy(contenidoAux + byteInicio, contenido, byteFin - byteInicio + 1);
	escribirBloqueGlobal(numBloque, contenidoAux);
	free(contenidoAux);
	return 0;
}

uint64_t deBloqueLocalAGlobal(uint64_t numBlockGroup, uint64_t numBlock) {
	//TODO REVISAR
	return staticGroupDescriptorTable[numBlockGroup].blockBitmap + numBlock;
}

uint64_t deBloqueGlobalALocal(uint64_t blocksPerGroup, uint64_t numBlock) {
	//TODO ESTO NO ES ASI
	return (div(numBlock, blocksPerGroup).quot);
}

//--------------------------------------------------
//LECTURA Y ESCRITURA DE ESTRUCTURAS EN EL DISCO
//--------------------------------------------------
//--------------------------------------------------
//LECTURA DEL SUPERBLOQUE
//--------------------------------------------------

superBlock_t leerSuperBlock(void) {
	pthread_rwlock_rdlock(&rwlockSuperBlock);
	char* contenido = leerBytes(1024, 1024);
	pthread_rwlock_unlock(&rwlockSuperBlock);
	superBlock_t superBloque;
	memcpy(&superBloque, contenido, 1024);
	free(contenido);
	if (staticSuperBlock.inicializado == 0) {
		staticSuperBlock.inodesCount = superBloque.inodesCount;
		staticSuperBlock.blocksCount = superBloque.blocksCount;
		staticSuperBlock.reservedBlocksCount = superBloque.reservedBlocksCount;
		staticSuperBlock.firstDataBlock = superBloque.firstDataBlock;
		staticSuperBlock.blockSize = 1024 * potencia(2, superBloque.blockSize);
		staticSuperBlock.fragmentSize = 1024 * potencia(2, superBloque.fragmentSize);
		staticSuperBlock.blocksPerGroup = superBloque.blocksPerGroup;
		staticSuperBlock.fragmentsPerGroup = superBloque.fragmentsPerGroup;
		staticSuperBlock.inodesPerGroup = superBloque.inodesPerGroup;
		staticSuperBlock.firstInode = superBloque.firstInode;
		staticSuperBlock.inodeSize = superBloque.inodeSize;
		staticSuperBlock.superBlockGroup = superBloque.superBlockGroup;
	}
	printf("------------------------------------------------------------\n");
	printf("Contenido del primer Super Bloque del disco:\n");
	printf("Cantidad Total de Inodos: [%d]\n", superBloque.inodesCount);
	printf("Cantidad Total de Bloques :[%d]\n", superBloque.blocksCount);
	printf("Cantidad de Bloques Reservados:[%d]\n", superBloque.reservedBlocksCount);
	printf("Cantidad de Bloques Libres: [%d]\n", superBloque.freeBlocksCount);
	printf("Cantidad de Inodos Libres: [%d]\n", superBloque.freeInodesCount);
	printf("Primer Bloque de Datos: [%d]\n", superBloque.firstDataBlock);
	printf("Tamanio de los Bloques(1024<<): [%d]\n", superBloque.blockSize);
	printf("Tamanio de los Fragmentos(1024<<): [%d]\n", superBloque.fragmentSize);
	printf("Cantidad de Bloques por Grupo de Bloques: [%d]\n", superBloque.blocksPerGroup);
	printf("Cantidad de Fragmentos por Grupo de Bloques: [%d]\n", superBloque.fragmentsPerGroup);
	printf("Cantidad de Inodos por Grupo de Bloques: [%d]\n", superBloque.inodesPerGroup);
	printf("Ultimo tiempo de montado: [%d]\n", superBloque.mTime);
	printf("Ultimo tiempo de acceso para escritura: [%d]\n", superBloque.wTime);
	printf("Cantidad de veces que se monto el File System: [%d]\n", superBloque.mntCount);
	printf("Maxima cantidad de montajes permitidos sin verificacion: [%d]\n", superBloque.mntMaxCount);
	printf("Magic Number: [%d]\n", superBloque.magic);
	printf("Estado del File System: [%d]\n", superBloque.state);
	printf("Manejo de Errores: [%d]\n", superBloque.errors);
	printf("Nivel de Menor Revision: [%d]\n", superBloque.minorRevLevel);
	printf("Ultimo Chequeo: [%d]\n", superBloque.lastCheck);
	printf("Maxica Cantidad de Intervalos de Tiempo entre Chequeos: [%d]\n", superBloque.checkInterval);
	printf("Sistema Operativo: [%d]\n", superBloque.creatorOS);
	printf("Nivel de Revision: [%d]\n", superBloque.revLevel);
	printf("defResUID: [%d]\n", superBloque.defResUID);
	printf("defResGID: [%d]\n", superBloque.defResGID);
	printf("Primer Inodo ASccesible: [%d]\n", superBloque.firstInode);
	printf("Tamanio de los Inodos: [%d]\n", superBloque.inodeSize);
	printf("Grupo de Super Bloque: [%d]\n", superBloque.superBlockGroup);
	printf("Funcionalidades Compatibles: [%d]\n", superBloque.featureCompat);
	printf("Funcionalidades incompatibles: [%d]\n", superBloque.featureIncompat);
	printf("feature ROcompat: [%d]\n", superBloque.featureROCompat);
	printf("UUID: [%s]\n", superBloque.UUID);
	printf("Nombre del Volumen: [%s]\n", superBloque.volumeName);
	printf("Ultimo Directorio Montado: [%s]\n", superBloque.lastMountedDirectory);
	printf("algoBitmap: [%d]\n", superBloque.algoBitmap);
	printf("preallocBlocks: [%d]\n", superBloque.preallocBlocks);
	printf("preallocDirBlocks: [%d]\n", superBloque.preallocDirBlocks);
	printf("Alineamiento: [%d]\n", superBloque.alignment);
	printf("Journal UUID: [%s]\n", superBloque.journalUUID);
	printf("Journal INum: [%d]\n", superBloque.journalINum);
	printf("Journal Dev: [%d]\n", superBloque.journalDev);
	printf("Ultimo Huerfano: [%d]\n", superBloque.lastOrphan);
	printf("------------------------------------------------------------\n");
	printf("Datos guardados en memoria sobre el Super Bloque:\n");
	printf("Cantidad Total de Inodos: [%d]\n", staticSuperBlock.inodesCount);
	printf("Cantidad Total de Bloques :[%d]\n", staticSuperBlock.blocksCount);
	printf("Cantidad de Bloques Reservados:[%d]\n", staticSuperBlock.reservedBlocksCount);
	printf("Primer Bloque de Datos: [%d]\n", staticSuperBlock.firstDataBlock);
	printf("Tamanio de los Bloques(1024<<): [%d]\n", staticSuperBlock.blockSize);
	printf("Tamanio de los Fragmentos(1024<<): [%d]\n", staticSuperBlock.fragmentSize);
	printf("Cantidad de Bloques por Grupo de Bloques: [%d]\n", staticSuperBlock.blocksPerGroup);
	printf("Cantidad de Fragmentos por Grupo de Bloques: [%d]\n", staticSuperBlock.fragmentsPerGroup);
	printf("Cantidad de Inodos por Grupo de Bloques: [%d]\n", staticSuperBlock.inodesPerGroup);
	printf("Primer Inodo ASccesible: [%d]\n", staticSuperBlock.firstInode);
	printf("Tamanio de los Inodos: [%d]\n", staticSuperBlock.inodeSize);
	printf("Grupo de Super Bloque: [%d]\n", staticSuperBlock.superBlockGroup);
	printf("------------------------------------------------------------\n");
	return superBloque;
}

void escribirSuperBloque(superBlock_t superBloque){
	char* bufferSuperBloque = (char*) malloc(1024);
	memcpy(bufferSuperBloque, &superBloque, 1024);
	escribirBytes(1024, 1024, bufferSuperBloque);
	free(bufferSuperBloque);
}

//--------------------------------------------------
//LECTURA DE LA GROUP DESCRIPTOR TABLE
//--------------------------------------------------

uint16_t cantBlockGroups(void) {
	//TODO REVISAR
	return staticSuperBlock.inodesCount / staticSuperBlock.inodesPerGroup;
}

uint64_t groupDescriptorTableSize(void) {
	return cantBlockGroups() * sizeof(groupDescriptor_t);
}

uint8_t bloqueInicioPrimerGroupDescriptorTable(void) {
	//TODO REVISAR
	return staticSuperBlock.firstDataBlock + 1;
}

uint16_t cantBloquesGroupDescriptorTable(void) {
	div_t division = div(groupDescriptorTableSize(), staticSuperBlock.blockSize);
	uint8_t cantBloques = division.quot;
	if (division.rem != 0) {
		cantBloques++;
	}
	return cantBloques;
}

groupDescriptor_t* leerGroupDescriptorTable(void) {
	//leo los bloques correspondientes
	char* contenido = (char*) malloc(groupDescriptorTableSize());
	uint16_t i;
	uint8_t bloqueInicio = bloqueInicioPrimerGroupDescriptorTable();
	uint16_t cantBloques = cantBloquesGroupDescriptorTable();
	for (i = 0; i < cantBloques - 1; i++) {
		char* contenidoAux = leerBloqueGlobal(bloqueInicio + i);
		memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, staticSuperBlock.blockSize);
		free(contenidoAux);
	}
	uint16_t resto = div(groupDescriptorTableSize(), staticSuperBlock.blockSize).rem;
	if (resto != 0) {
		char* contenidoAux = leerParteBloqueGlobal(bloqueInicio + i, 0, resto);
		memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, resto);
		free(contenidoAux);
	} else {
		char* contenidoAux = leerBloqueGlobal(bloqueInicio + i);
		memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, staticSuperBlock.blockSize);
		free(contenidoAux);
	}
	groupDescriptor_t *groupDescriptor = (groupDescriptor_t*) malloc(groupDescriptorTableSize());
	memcpy(groupDescriptor, contenido, groupDescriptorTableSize());
	free(contenido);
	// TEST BEGIN
	printf("------------------------------------------------------------\n");
	printf("Datos guardados en memoria sobre la Group Descriptor Table:\n");
	for (i = 0; i < cantBlockGroups(); i++) {
		printf("Grupo [%d]:\n", i);
		printf("-----Primer Bloque del Group Bitmap: [%d].\n", groupDescriptor[i].blockBitmap);
		printf("-----Primer Bloque del Inode Bitmap: [%d].\n", groupDescriptor[i].inodeBitmap);
		printf("-----Primer Bloque de la Inode Table: [%d].\n", groupDescriptor[i].inodeTable);
		printf("-----Cantidad de Bloques libres: [%d].\n", groupDescriptor[i].freeBlocksCount);
		printf("-----Cantidad de Inodos libres: [%d].\n", groupDescriptor[i].freeInodesCount);
		printf("-----Cantidad de Inodos dedicados a Directorios: [%d].\n", groupDescriptor[i].dirsCount);
		printf("Pad: [%d].\n", groupDescriptor[i].pad);
	}
	printf("------------------------------------------------------------\n");
	// TEST END
	if (staticGroupDescriptorTable == NULL) {
		cargarStaticGroupDescriptorTable(groupDescriptor);
	}
	return groupDescriptor;
}

void escribirGroupDescriptorTable(groupDescriptor_t* groupDescriptorTable) {
	char* bufferGroupDescriptorTable = (char*) malloc(groupDescriptorTableSize());
	memcpy(bufferGroupDescriptorTable, groupDescriptorTable, groupDescriptorTableSize());
	uint16_t i;
	uint8_t bloqueInicio = bloqueInicioPrimerGroupDescriptorTable();
	uint16_t cantBloques = cantBloquesGroupDescriptorTable();
	for (i = 0; i < cantBloques - 1; i++) {
		escribirBytes(bloqueInicio + i, staticSuperBlock.blockSize, bufferGroupDescriptorTable + (i * staticSuperBlock.blockSize));
	}
	uint16_t resto = div(groupDescriptorTableSize(), staticSuperBlock.blockSize).rem;
	//TODO esto puede traer el mismo error que el offset de la lectura de bloques en caso que el offset sea igual al tamanio de bloques
	if (resto != 0) {
		escribirBytes(bloqueInicio + i, resto, bufferGroupDescriptorTable + (i * staticSuperBlock.blockSize));
	} else {
		escribirBytes(bloqueInicio + i, staticSuperBlock.blockSize, bufferGroupDescriptorTable + (i * staticSuperBlock.blockSize));
	}
}

void cargarStaticGroupDescriptorTable(groupDescriptor_t* groupDescriptorTable) {
	staticGroupDescriptorTable = (staticGroupDescriptor_t*) malloc(cantBlockGroups() * sizeof(staticGroupDescriptor_t));
	uint16_t i;
	for (i = 0; i < cantBlockGroups(); i++) {
		staticGroupDescriptorTable[i].blockBitmap = groupDescriptorTable[i].blockBitmap;
		staticGroupDescriptorTable[i].inodeBitmap = groupDescriptorTable[i].inodeBitmap;
		staticGroupDescriptorTable[i].inodeTable = groupDescriptorTable[i].inodeTable;
	}
	//TEST BEGIN
	printf("------------------------------------------------------------\n");
	printf("Contenido de la primer Group Descriptor Table:\n");
	for (i = 0; i < cantBlockGroups(); i++) {
		printf("Grupo [%d]:\n", i);
		printf("-----Primer Bloque del Group Bitmap: [%d].\n", staticGroupDescriptorTable[i].blockBitmap);
		printf("-----Primer Bloque del Inode Bitmap: [%d].\n", staticGroupDescriptorTable[i].inodeBitmap);
		printf("-----Primer Bloque de la Inode Table: [%d].\n", staticGroupDescriptorTable[i].inodeTable);
	}
	printf("------------------------------------------------------------\n");
	// TEST END
}

//--------------------------------------------------
//LECTURA Y ESCRITURA DE BITMAPS
//--------------------------------------------------
//--------------------------------------------------
//LECTURA Y ESCRITURA DEL BLOCK BITMAP
//--------------------------------------------------

uint64_t blockBitmapSize(void) {
	//TODO revisar
	return staticSuperBlock.blocksPerGroup / 8;
}

uint16_t cantBloquesBlockBitmap(void) {
	div_t division = div(blockBitmapSize(), staticSuperBlock.blockSize);
	uint8_t cantBloques = division.quot;
	if (division.rem != 0) {
		cantBloques++;
	}
	return cantBloques;
}

byteBitmap_t* leerBlockBitmap(uint8_t numBlockGroup){
	char* contenido = (char*) malloc(blockBitmapSize());
	uint16_t i;
	uint8_t bloqueInicio = staticGroupDescriptorTable[numBlockGroup].blockBitmap;
	uint16_t cantBloques = cantBloquesBlockBitmap();
	for (i = 0; i < cantBloques - 1; i++) {
		char* contenidoAux = leerBloqueGlobal(bloqueInicio + i);
		memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, staticSuperBlock.blockSize);
		free(contenidoAux);
	}
	uint16_t resto = div(blockBitmapSize(), staticSuperBlock.blockSize).rem;
	if (resto != 0) {
		char* contenidoAux = leerParteBloqueGlobal(bloqueInicio + i, 0, resto);
		memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, resto);
		free(contenidoAux);
	} else {
		char* contenidoAux = leerBloqueGlobal(bloqueInicio + i);
		memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, staticSuperBlock.blockSize);
		free(contenidoAux);
	}
	byteBitmap_t *blockBitmap = (byteBitmap_t*) malloc(blockBitmapSize());
	memcpy(blockBitmap, contenido, blockBitmapSize());
	free(contenido);
	return blockBitmap;
}

uint8_t escribirBlockBitmap(uint8_t numBlockGroup, byteBitmap_t* blockBitmap){
	//TODO
	return 0;
}

uint8_t estaOcupadoBloque(byteBitmap_t* blockBitmap, uint64_t numBloque) {
	div_t division = div(numBloque, 8);
	uint64_t numByte = division.quot;
	uint8_t numBit = division.rem;
	uint8_t retorno;
	switch (numBit) {
	case 0:
		retorno = blockBitmap[numByte].byte0;
		break;
	case 1:
		retorno = blockBitmap[numByte].byte1;
		break;
	case 2:
		retorno = blockBitmap[numByte].byte2;
		break;
	case 3:
		retorno = blockBitmap[numByte].byte3;
		break;
	case 4:
		retorno = blockBitmap[numByte].byte4;
		break;
	case 5:
		retorno = blockBitmap[numByte].byte5;
		break;
	case 6:
		retorno = blockBitmap[numByte].byte6;
		break;
	case 7:
		retorno = blockBitmap[numByte].byte7;
		break;
	}
	return retorno;
}

void liberarBloqueOcupadoEnBitmap(byteBitmap_t* blockBitmap, uint64_t numBloque) {
	//TODO REVISAR EL MANEJO DE BITS
	div_t division = div(numBloque, 8);
	uint64_t numByte = division.quot;
	uint8_t numBit = division.rem;
	switch (numBit) {
	case 0:
		blockBitmap[numByte].byte0 = 0;
		break;
	case 1:
		blockBitmap[numByte].byte1 = 0;
		break;
	case 2:
		blockBitmap[numByte].byte2 = 0;
		break;
	case 3:
		blockBitmap[numByte].byte3 = 0;
		break;
	case 4:
		blockBitmap[numByte].byte4 = 0;
		break;
	case 5:
		blockBitmap[numByte].byte5 = 0;
		break;
	case 6:
		blockBitmap[numByte].byte6 = 0;
		break;
	case 7:
		blockBitmap[numByte].byte7 = 0;
		break;
	}
}

void ocuparBloqueLibreEnBitmap(byteBitmap_t* blockBitmap, uint64_t numBloque) {
	//TODO REVISAR EL MANEJO DE BITS
	div_t division = div(numBloque, 8);
	uint64_t numByte = division.quot;
	uint8_t numBit = division.rem;
	switch (numBit) {
	case 0:
		blockBitmap[numByte].byte0 = 1;
		break;
	case 1:
		blockBitmap[numByte].byte1 = 1;
		break;
	case 2:
		blockBitmap[numByte].byte2 = 1;
		break;
	case 3:
		blockBitmap[numByte].byte3 = 1;
		break;
	case 4:
		blockBitmap[numByte].byte4 = 1;
		break;
	case 5:
		blockBitmap[numByte].byte5 = 1;
		break;
	case 6:
		blockBitmap[numByte].byte6 = 1;
		break;
	case 7:
		blockBitmap[numByte].byte7 = 1;
		break;
	}
}

int8_t liberarBloqueOcupado(uint8_t numBlockGroup, uint32_t numBloque){
	byteBitmap_t* blockBitmap = leerBlockBitmap(numBlockGroup);
	liberarBloqueOcupadoEnBitmap(blockBitmap, numBloque);
	escribirBlockBitmap(numBlockGroup, blockBitmap);
	superBlock_t superBloque = leerSuperBlock();
	superBloque.freeBlocksCount++;
	escribirSuperBloque(superBloque);
	groupDescriptor_t* groupDescriptorTable = leerGroupDescriptorTable();
	groupDescriptorTable[numBlockGroup].freeBlocksCount++;
	escribirGroupDescriptorTable(groupDescriptorTable);
	return 0;
}

int64_t buscarBloqueLibreEnBitmap(byteBitmap_t * blockBitmap) {
	uint64_t encontrado = -1, i;
	for (i = 0; (i < staticSuperBlock.blocksPerGroup) && (encontrado == -1); i++) {
		if (!(estaOcupadoBloque(blockBitmap, i)))
			encontrado = i;
	}
	return encontrado;
}

uint32_t* buscarYOcuparNBloquesLibres(uint8_t numBlockGroup, uint32_t cantBloques){
	return NULL;
}

int64_t buscarYOcuparBloqueLibre(uint8_t numBlockGroup){
	byteBitmap_t* blockBitmap = leerBlockBitmap(numBlockGroup);
	int64_t numBlock = buscarBloqueLibreEnBitmap(blockBitmap);
	if(numBlock > 0){
		ocuparBloqueLibreEnBitmap(blockBitmap, numBlock);
		escribirBlockBitmap(numBlockGroup, blockBitmap);
		superBlock_t superBloque = leerSuperBlock();
		superBloque.freeBlocksCount--;
		escribirSuperBloque(superBloque);
		groupDescriptor_t* groupDescriptorTable = leerGroupDescriptorTable();
		groupDescriptorTable[numBlockGroup].freeBlocksCount--;
		escribirGroupDescriptorTable(groupDescriptorTable);
		return numBlock;
	}else{
		return -1;
	}
}

//--------------------------------------------------
//LECTURA Y ESCRITURA DEL INODE BITMAP
//--------------------------------------------------

uint64_t inodeBitmapSize(void) {
	//TODO revisar
	return staticSuperBlock.inodesPerGroup / 8;
}

uint16_t cantBloquesInodeBitmap(void) {
	div_t division = div(inodeBitmapSize(), staticSuperBlock.blockSize);
	uint8_t cantBloques = division.quot;
	if (division.rem != 0) {
		cantBloques++;
	}
	return cantBloques;
}

byteBitmap_t* leerInodeBitmap(uint8_t numBlockGroup){
	char* contenido = (char*) malloc(inodeBitmapSize());
	uint16_t i;
	uint8_t bloqueInicio = staticGroupDescriptorTable[numBlockGroup].inodeBitmap;
	uint16_t cantBloques = cantBloquesInodeBitmap();
	for (i = 0; i < cantBloques - 1; i++) {
		char* contenidoAux = leerBloqueGlobal(bloqueInicio + i);
		memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, staticSuperBlock.blockSize);
		free(contenidoAux);
	}
	uint16_t resto = div(inodeBitmapSize(), staticSuperBlock.blockSize).rem;
	if (resto != 0) {
		char* contenidoAux = leerParteBloqueGlobal(bloqueInicio + i, 0, resto);
		memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, resto);
		free(contenidoAux);
	} else {
		char* contenidoAux = leerBloqueGlobal(bloqueInicio + i);
		memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, staticSuperBlock.blockSize);
		free(contenidoAux);
	}
	byteBitmap_t *inodeBitmap = (byteBitmap_t*) malloc(inodeBitmapSize());
	memcpy(inodeBitmap, contenido, blockBitmapSize());
	free(contenido);
	return inodeBitmap;
}

uint8_t escribirInodeBitmap(uint8_t numBlockGroup, byteBitmap_t* blockBitmap){
	//TODO
	return 0;
}

uint8_t estaOcupadoInodo(byteBitmap_t* inodeBitmap, uint64_t numInodo) {
	div_t division = div(numInodo, 8);
	uint64_t numByte = division.quot;
	uint8_t numBit = division.rem;
	uint8_t retorno;
	switch (numBit) {
	case 0:
		retorno = inodeBitmap[numByte].byte0;
		break;
	case 1:
		retorno = inodeBitmap[numByte].byte1;
		break;
	case 2:
		retorno = inodeBitmap[numByte].byte2;
		break;
	case 3:
		retorno = inodeBitmap[numByte].byte3;
		break;
	case 4:
		retorno = inodeBitmap[numByte].byte4;
		break;
	case 5:
		retorno = inodeBitmap[numByte].byte5;
		break;
	case 6:
		retorno = inodeBitmap[numByte].byte6;
		break;
	case 7:
		retorno = inodeBitmap[numByte].byte7;
		break;
	}
	return retorno;
}

void liberarInodoOcupadoEnBitmap(byteBitmap_t* inodeBitmap, uint64_t numBloque) {
	//TODO REVISAR EL MANEJO DE BITS
	div_t division = div(numBloque, 8);
	uint64_t numByte = division.quot;
	uint8_t numBit = division.rem;
	switch (numBit) {
	case 0:
		inodeBitmap[numByte].byte0 = 0;
		break;
	case 1:
		inodeBitmap[numByte].byte1 = 0;
		break;
	case 2:
		inodeBitmap[numByte].byte2 = 0;
		break;
	case 3:
		inodeBitmap[numByte].byte3 = 0;
		break;
	case 4:
		inodeBitmap[numByte].byte4 = 0;
		break;
	case 5:
		inodeBitmap[numByte].byte5 = 0;
		break;
	case 6:
		inodeBitmap[numByte].byte6 = 0;
		break;
	case 7:
		inodeBitmap[numByte].byte7 = 0;
		break;
	}
}

void ocuparInodoLibreEnBitmap(byteBitmap_t* inodeBitmap, uint64_t numBloque) {
	//TODO REVISAR EL MANEJO DE BITS
	div_t division = div(numBloque, 8);
	uint64_t numByte = division.quot;
	uint8_t numBit = division.rem;
	switch (numBit) {
	case 0:
		inodeBitmap[numByte].byte0 = 1;
		break;
	case 1:
		inodeBitmap[numByte].byte1 = 1;
		break;
	case 2:
		inodeBitmap[numByte].byte2 = 1;
		break;
	case 3:
		inodeBitmap[numByte].byte3 = 1;
		break;
	case 4:
		inodeBitmap[numByte].byte4 = 1;
		break;
	case 5:
		inodeBitmap[numByte].byte5 = 1;
		break;
	case 6:
		inodeBitmap[numByte].byte6 = 1;
		break;
	case 7:
		inodeBitmap[numByte].byte7 = 1;
		break;
	}
}

int8_t liberarInodoOcupado(uint8_t numBlockGroup, uint32_t numBloque, uint8_t esDir){
	byteBitmap_t* inodeBitmap = leerInodeBitmap(numBlockGroup);
	liberarInodoOcupadoEnBitmap(inodeBitmap, numBloque);
	escribirInodeBitmap(numBlockGroup, inodeBitmap);
	superBlock_t superBloque = leerSuperBlock();
	superBloque.freeInodesCount++;
	escribirSuperBloque(superBloque);
	groupDescriptor_t* groupDescriptorTable = leerGroupDescriptorTable();
	groupDescriptorTable[numBlockGroup].freeInodesCount++;
	if(esDir){
		groupDescriptorTable[numBlockGroup].dirsCount--;
	}
	escribirGroupDescriptorTable(groupDescriptorTable);
	return 0;
}

int64_t buscarInodoLibreEnBitmap(byteBitmap_t *inodeBitmap) {
	uint64_t encontrado = -1, i;
	for (i = 0; (i < staticSuperBlock.inodesPerGroup) && (encontrado == -1); i++) {
		if (!(estaOcupadoInodo(inodeBitmap, i)))
			encontrado = i;
	}
	return encontrado;
}

int64_t buscarYOcuparInodoLibre(uint8_t numBlockGroup, uint8_t esDir){
	byteBitmap_t* inodeBitmap = leerInodeBitmap(numBlockGroup);
	int64_t numBlock = buscarInodoLibreEnBitmap(inodeBitmap);
	if(numBlock > 0){
		ocuparInodoLibreEnBitmap(inodeBitmap, numBlock);
		escribirInodeBitmap(numBlockGroup, inodeBitmap);
		superBlock_t superBloque = leerSuperBlock();
		superBloque.freeInodesCount--;
		escribirSuperBloque(superBloque);
		groupDescriptor_t* groupDescriptorTable = leerGroupDescriptorTable();
		groupDescriptorTable[numBlockGroup].freeInodesCount--;
		if(esDir){
			groupDescriptorTable[numBlockGroup].dirsCount++;
		}
		escribirGroupDescriptorTable(groupDescriptorTable);
		return numBlock;
	}else{
		return -1;
	}
}

//--------------------------------------------------
//LECTURA DE LA INODE TABLE
//--------------------------------------------------

void imprimirContenidoInodo(inodeStructure_t inodo) {
	printf("-----Modo: [%d].\n", inodo.mode);
	printf("-----UID: [%d].\n", inodo.UID);
	printf("-----Tamanio: [%d].\n", inodo.size);
	printf("-----Ultimo Tiempo de Acceso: [%d].\n", inodo.aTime);
	printf("-----Tiempo de Creacion: [%d].\n", inodo.cTime);
	printf("-----Ultimo Tiempo de Modificacion: [%d].\n", inodo.mTime);
	printf("-----Ultimo Tiempo de Eliminacion: [%d].\n", inodo.dTime);
	printf("-----GID: [%d].\n", inodo.GID);
	printf("-----Cantidad de veces que el Inodo es referenciado: [%d].\n", inodo.linksCount);
	printf("-----Cantidad de Bloques asociados a este archivo: [%d].\n", inodo.blocks);
	printf("-----Flags: [%d].\n", inodo.flags);
	printf("-----OSD1: [%d].\n", inodo.osd1);
	printf("-----Primer Direccionamiento Directo: [%d].\n", (inodo.block)[0]);
	printf("-----Segundo Direccionamiento Directo: [%d].\n", (inodo.block)[1]);
	printf("-----Tercer Direccionamiento Directo: [%d].\n", (inodo.block)[2]);
	printf("-----Cuarto Direccionamiento Directo: [%d].\n", (inodo.block)[3]);
	printf("-----Quinto Direccionamiento Directo: [%d].\n", (inodo.block)[4]);
	printf("-----Sexto Direccionamiento Directo: [%d].\n", (inodo.block)[5]);
	printf("-----Septimo Direccionamiento Directo: [%d].\n", (inodo.block)[6]);
	printf("-----Octavo Direccionamiento Directo: [%d].\n", (inodo.block)[7]);
	printf("-----Noveno Direccionamiento Directo: [%d].\n", (inodo.block)[8]);
	printf("-----Decimo Direccionamiento Directo: [%d].\n", (inodo.block)[9]);
	printf("-----Decimoprimer Direccionamiento Directo: [%d].\n", (inodo.block)[10]);
	printf("-----Decimosegundo Direccionamiento Directo: [%d].\n", (inodo.block)[11]);
	printf("-----Primer Direccionamiento Indirecto Simple: [%d].\n", (inodo.block)[12]);
	printf("-----Primer Direccionamiento Indirecto Doble: [%d].\n", (inodo.block)[13]);
	printf("-----Primer Direccionamiento Indirecto Triple: [%d].\n", (inodo.block)[14]);
	printf("-----Version: [%d].\n", inodo.generation);
	printf("-----File ACL: [%d].\n", inodo.fileACL);
	printf("-----Directory ACL: [%d].\n", inodo.dirACL);
	printf("-----Ubicacion del ultimo fragmento del archivo: [%d].\n", inodo.fAddr);
}

inodeStructure_t* leerInodeTable(uint8_t numBlockGroup) {
	if (numBlockGroup < cantBlockGroups()) {
		uint64_t primerBloque = staticGroupDescriptorTable[numBlockGroup].inodeTable;
		uint64_t bytesInodeTable = inodeTableSize();
		char* contenido = (char*) malloc(bytesInodeTable);

		uint32_t cantBloques;
		div_t division = div(bytesInodeTable, staticSuperBlock.blockSize);
		if (division.rem != 0) {
			cantBloques = division.quot + 1;
		} else {
			cantBloques = division.quot;
		}

		uint32_t i;
		for (i = 0; i < cantBloques - 1; i++) {
			char* contenidoAux = leerBloqueGlobal(primerBloque + i);
			memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, staticSuperBlock.blockSize);
			free(contenidoAux);
		}
		if (division.rem != 0) {
			char* contenidoAux = leerParteBloqueGlobal(primerBloque + i, 0, division.rem);
			memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, division.rem);
			free(contenidoAux);
		} else {
			char* contenidoAux = leerBloqueGlobal(primerBloque + i);
			memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoAux, staticSuperBlock.blockSize);
			free(contenidoAux);
		}
		inodeStructure_t* inodeTable = (inodeStructure_t*) malloc(bytesInodeTable);
		memcpy(inodeTable, contenido, bytesInodeTable);
		free(contenido);
		//TEST BEGIN
		//printf("------------------------------------------------------------\n");
		//printf("Contenido de la Inode Table del Block Group [%d]:\n", numBlockGroup);
		//for (i = 0; i < 20/*staticSuperBlock.inodesPerGroup*/; i++) {
			//printf("Inodo [%d]:\n", i);
			//imprimirContenidoInodo(inodeTable[i]);
		//}
		//TEST END
		return inodeTable;
	} else {
		return NULL;
	}
}

inodeStructure_t leerInodo(uint32_t numInodo){
	//TODO
	inodeStructure_t inodo;
	return inodo;
}

void escribirInodo(inodeStructure_t inodo, uint32_t numInodo){
	//TODO
}

uint64_t inodeTableSize() {
	return staticSuperBlock.inodesPerGroup * sizeof(inodeStructure_t);
}

/*char* leerParteArchivo(inodeStructure_t inodo, uint64_t numBlockGroup, uint64_t blocksPerGroup, uint64_t byteDesde, uint64_t byteHasta){
 uint64_t primerBloqueArchivoALeer = div(byteDesde, staticSuperBlock.blockSize).quot;
 uint64_t desplazamientoPrimerBloqueArchivo = div(byteDesde, staticSuperBlock.blockSize).rem;
 uint64_t ultimoBloqueArchivoALeer = div(byteHasta, staticSuperBlock.blockSize).quot;
 uint64_t desplazamientoUltimoBloqueArchivo = div(byteHasta, staticSuperBlock.blockSize).rem;
 char* contenido = NULL;//(char*) malloc(byteHasta - byteDesde + 1);

 if(primerBloqueArchivoALeer == ultimoBloqueArchivoALeer){
 if(primerBloqueArchivoALeer < 13){
 //EL INODO DIRECCIONA DIRECTAMENTE AL BLOQUE
 contenido = leerParteBloqueLocal(numBlockGroup, blocksPerGroup, inodo.block[primerBloqueArchivoALeer], desplazamientoPrimerBloqueArchivo, desplazamientoUltimoBloqueArchivo);
 }else if(primerBloqueArchivoALeer >= 13 && primerBloqueArchivoALeer < ((staticSuperBlock.blockSize / 4) + 13)){
 //EL INODO APUNTA A UN BLOQUE CON DIRECCIONES DE BLOQUE
 uint32_t* tablaBloques = obtenerTablaDeBloques(numBlockGroup, blocksPerGroup, inodo.block[13]);
 uint64_t numBloque = primerBloqueArchivoALeer - 13;
 contenido = leerParteBloqueLocal(numBlockGroup, blocksPerGroup, tablaBloques[numBloque], desplazamientoPrimerBloqueArchivo, desplazamientoUltimoBloqueArchivo);
 }else if(primerBloqueArchivoALeer >= ((staticSuperBlock.blockSize / 4) + 13) && primerBloqueArchivoALeer < ((staticSuperBlock.blockSize * staticSuperBlock.blockSize / 4) + (staticSuperBlock.blockSize / 4) + 13)){
 //EL INODO APUNTA A UN BLOQUE CON PUNTEROS A BLOQUES CON DIRECCIONES DE BLOQUE

 }
 }
 if(primerBloqueArchivoALeer < 13){
 //LOS PRIMEROS NUMEROS DE BLOQUE ESTAN EN EL INODO
 uint64_t i;
 for(i = primerBloqueArchivoALeer; i < 13 && i < ultimoBloqueArchivoALeer;)
 }else{
 //TENGO QUE LEER LAS TABLAS CORRESPONDIENTES
 }





 uint64_t cantBloquesCompletos = div(inodo.size, staticSuperBlock.blockSize).quot;
 uint64_t bytesUltimoBloque = div(inodo.size, staticSuperBlock.blockSize).rem;
 memset(contenido, '\0', inodo.size);
 uint64_t i;
 for(i = 0; i < 13 && i < cantBloquesCompletos; i++){
 char* contenidoBloque = leerBloqueLocal(numBlockGroup, blocksPerGroup, inodo.block[i]);
 memcpy(contenido + (i * staticSuperBlock.blockSize), contenidoBloque, staticSuperBlock.blockSize);
 free(contenidoBloque);
 }
 if(i == 13 && cantBloquesCompletos >= 13){
 uint32_t* tablaDeBloques = obtenerTablaDeBloques(numBlockGroup, blocksPerGroup, inodo.block[i]);
 uint64_t cantBloquesEnTabla = staticSuperBlock.blockSize / 4;
 for(; i < cantBloquesEnTabla && i < cantBloquesCompletos; i++){

 }
 }else if(i == 13 && cantBloquesCompletos < 13){

 }else{

 }
 }*/

uint32_t* obtenerTablaDeBloques(uint64_t numBlockGroup, uint64_t numBlock) {
	char* contenidoBloque = leerBloqueLocal(numBlockGroup, numBlock);
	uint32_t* tabla = NULL;
	if (contenidoBloque != NULL) {
		tabla = (uint32_t*) malloc(staticSuperBlock.blockSize);
		memset(tabla, '0', staticSuperBlock.blockSize);
		memcpy(tabla, contenidoBloque, staticSuperBlock.blockSize);
	}
	free(contenidoBloque);
	return tabla;
}

void encolarBloque(nodoBloque_t** colaBloquesFte, nodoBloque_t** colaBloquesFin, char bloque[staticSuperBlock.blockSize]) {
	nodoBloque_t* nue = (nodoBloque_t*) malloc(sizeof(nodoBloque_t));
	memcpy(nue->contenidoBloque, bloque, staticSuperBlock.blockSize);
	nue->sig = NULL;

	if (*colaBloquesFte == NULL) {
		*colaBloquesFte = nue;
	} else {
		(*colaBloquesFin)->sig = nue;
	}
	*colaBloquesFin = nue;
}

char* desencolarBloque(nodoBloque_t** colaBloquesFte, nodoBloque_t** colaBloquesFin) {
	char* contenidoBloque = (char*) malloc(staticSuperBlock.blockSize);
	memcpy(contenidoBloque, (*colaBloquesFte)->contenidoBloque, staticSuperBlock.blockSize);

	nodoBloque_t* aux = malloc(sizeof(nodoBloque_t));
	aux = *colaBloquesFte;
	*colaBloquesFte = (*colaBloquesFte)->sig;
	if (*colaBloquesFte == NULL) {
		*colaBloquesFin = NULL;
	}
	free(aux);
	return contenidoBloque;
}

uint64_t cantidadNodosBloques(nodoBloque_t* colaBloquesFte, nodoBloque_t* colaBloquesFin) {
	uint64_t i;
	nodoBloque_t* aux;
	for (i = 0, aux = colaBloquesFte; aux != NULL; aux = aux->sig, i++)
		;
	return i;
}
//----------------------------------------------------------------------------------------------------
//INDIRECCIONAMIENTOS
//----------------------------------------------------------------------------------------------------

uint64_t maxCantBloquesIndirectosSimples() {
	return staticSuperBlock.blockSize / sizeof(uint32_t);
}

uint64_t maxCantBloquesIndirectosDobles() {
	return staticSuperBlock.blockSize * staticSuperBlock.blockSize / sizeof(uint32_t);
}

uint64_t maxCantBloquesIndirectosTriples() {
	return staticSuperBlock.blockSize * staticSuperBlock.blockSize * staticSuperBlock.blockSize / sizeof(uint32_t);
}

char* leerNBloquesNivel0(uint8_t blockGroup, uint32_t* puntDir, off_t byteOffset, size_t sizeBytes) {
	//printf("Leo los direccionamientos directos.\n");
	char* contenido = NULL;
	//printf("Tengo que leer [%d] bytes desde el byte [%d].\n", (uint32_t) sizeBytes, (uint32_t) byteOffset);
	if (sizeBytes > 0) {
		uint64_t byteFin = byteOffset + sizeBytes;
		div_t divInicio = div(byteOffset, staticSuperBlock.blockSize);
		uint16_t bloqueInicio = divInicio.quot;
		//printf("Tengo que leer el a partir del bloque [%d] con un offset de [%d].\n", bloqueInicio, divInicio.rem);
		div_t divFin = div(byteFin, staticSuperBlock.blockSize);
		uint16_t bloqueFin = divFin.quot;
		off_t offsetFinal = divFin.rem;
		//printf("Hasta el bloque [%d] con un offset de [%d].\n", bloqueFin, (uint32_t) offsetFinal);
		//printf("Bloque inicio:[%d]\n", bloqueInicio);
		if(divFin.rem == 0){
			bloqueFin--;
			offsetFinal = 1024; //TODO revisar que esto sea realmente necesario
			//printf("Como el offset es 0 seteo el bloque final a [%d] y el offset a [%d].\n", bloqueFin, (uint32_t) offsetFinal);
		}
		uint16_t punteroActual;
		contenido = malloc(sizeBytes);

		if (bloqueInicio == bloqueFin) {
			//EL PRIMERO TAMBIEN ES EL ULTIMO
			//printf("El primer bloque tambien es el ultimo.\n");
			punteroActual = bloqueInicio;
			//printf("Leo el contenido del bloque.\n");
			char* contenidoBloque = leerBloqueGlobal(puntDir[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			memcpy(contenido, contenidoBloque + divInicio.rem, sizeBytes);
			//printf("El contenido necesario del bloque es:\n");
			//uint32_t i;
			//for(i = 0; i < sizeBytes; i++){
				//printf("Byte:[%d] -- Contenido:[%d]:[%c]\n", i, (uint32_t) contenido[i], (uint32_t) contenido[i]);
			//}
			free(contenidoBloque);
		} else {
			//EL PRIMERO NO ES EL ULTIMO
			//printf("El primer bloque no es el ultimo.\n");
			//LEO EL PRIMERO
			//printf("Leo el primer bloque.\n");
			off_t offsetGrabacion = 0;
			punteroActual = bloqueInicio;
			char* contenidoBloque = leerBloqueGlobal(puntDir[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			memcpy(contenido, contenidoBloque + divInicio.rem, staticSuperBlock.blockSize - divInicio.rem);
			//printf("El contenido necesario del bloque es:\n");
			//uint32_t i;
			//for(i = 0; i < staticSuperBlock.blockSize - divInicio.rem; i++){
				//printf("Byte:[%d] -- Contenido:[%d]:[%c]\n", i, (uint32_t) contenido[i], (uint32_t) contenido[i]);
			//}

			free(contenidoBloque);
			offsetGrabacion = staticSuperBlock.blockSize - divInicio.rem;
			punteroActual++;
			//LEO LOS DEL MEDIO
			//printf("Leo los punteros del medio.\n");
			//SI SOLO SON DOS NO VA A ENTRAR EN EL FOR
			for (; punteroActual < bloqueFin; punteroActual++, offsetGrabacion += staticSuperBlock.blockSize) {
				//printf("El offset de grabacion se setea a: [%d]\n", (int32_t) offsetGrabacion);
				contenidoBloque = leerBloqueGlobal(puntDir[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
				memcpy(contenido + offsetGrabacion, contenidoBloque, staticSuperBlock.blockSize);
				free(contenidoBloque);

			}

			//LEO EL DEL FINAL
			//printf("Leo el puntero final.\n");
			//EL PUNTERO ACTUAL ES EL PUNTERO FINAL
			contenidoBloque = leerBloqueGlobal(puntDir[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			//uint64_t j;
			//for(j = 0; j < offsetFinal;j++){
				//printf("contenido Bloque [%d]:[%d]:[%c]\n", (uint32_t) j ,(uint32_t) contenidoBloque[j],contenidoBloque[j]);
			//}
			//printf("offset final: [%d]\n", (uint32_t) offsetFinal);
			//printf("Numero de Bloque a leer: puntDir[%d] = [%d].\n", punteroActual, puntDir[punteroActual]);
			//printf("offset de grabacion: [%d]\n", (uint32_t) offsetGrabacion);
			memcpy(contenido + offsetGrabacion, contenidoBloque, offsetFinal);
			free(contenidoBloque);
		}
	}
	/*uint32_t i;
	for (i = 0; i < sizeBytes; i++) {
		printf("[%d]:[%d]:[%c].\n", i, contenido[i], contenido[i]);
	}*/
	return contenido;
}

char* leerNBloquesNivel1(uint8_t blockGroup, uint32_t* puntInd, off_t byteOffset, size_t sizeBytes) {
	//printf("Leo los direccionamientos indirectos.\n");
	char* contenido = NULL;
	if (sizeBytes > 0) {
		uint64_t byteFin = byteOffset + sizeBytes;
		//printf("Tengo que leer [%d] bytes desde el byte [%d].\n", (uint32_t) sizeBytes, (uint32_t) byteOffset);
		div_t divInicio = div(byteOffset, maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize);
		uint16_t punteroIndInicio = divInicio.quot;
		//printf("Tengo que empezar por el puntero [%d].\n", punteroIndInicio);
		div_t divFin = div(byteFin, maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize);
		uint16_t punteroIndFin = divFin.quot;
		//printf("Tengo que leer hasta el puntero [%d].\n", punteroIndFin);
		off_t offsetFinal = divFin.rem;
		if(divFin.rem == 0){
			punteroIndFin--;
			offsetFinal = 1024; //TODO revisar que esto sea realmente necesario
			//printf("Como el offset es 0 seteo el bloque final a [%d] y el offset a [%d].\n", punteroIndFin, (uint32_t) offsetFinal);
		}

		uint16_t punteroActual;
		contenido = malloc(sizeBytes);

		if (punteroIndInicio == punteroIndFin) {
			//EL PRIMERO TAMBIEN ES EL ULTIMO
			//printf("El primer puntero tambien es el ultimo.\n");
			punteroActual = punteroIndInicio;
			char* contenidoBloque = leerBloqueGlobal(puntInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			uint32_t* puntDir = malloc(staticSuperBlock.blockSize);
			memcpy(puntDir, contenidoBloque, staticSuperBlock.blockSize);
			//printf("El contenido del bloque de direcciones es:\n");
			//uint32_t i;
			//for(i = 0; i < staticSuperBlock.blockSize / sizeof(uint32_t); i++){
				//printf("Puntero [%d] = [%d].\n", i, puntDir[i]);
			//}
			free(contenidoBloque);
			//printf("Leo los direccionamientos directos del bloque.\n");
			char* contenidoAux = leerNBloquesNivel0(blockGroup, puntDir, divInicio.rem, sizeBytes);
			//printf("El resultado de la lectura es:\n");
			//for(i = 0; i < sizeBytes; i++){
				//printf("Byte:[%d] -- Contenido:[%d]:[%c]\n", i, (uint32_t) contenidoAux[i], (uint32_t) contenidoAux[i]);
			//}
			free(puntDir);
			memcpy(contenido, contenidoAux, sizeBytes);
			free(contenidoAux);
		} else {
			//EL PRIMERO NO ES EL ULTIMO
			//LEO EL PRIMERO
			off_t offsetGrabacion = 0;
			punteroActual = punteroIndInicio;
			char* contenidoBloque = leerBloqueGlobal(puntInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			uint32_t* puntDir = malloc(staticSuperBlock.blockSize);
			memcpy(puntDir, contenidoBloque, staticSuperBlock.blockSize);
			free(contenidoBloque);
			char* contenidoAux = leerNBloquesNivel0(blockGroup, puntDir, divInicio.rem, (maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize) - divInicio.rem);
			free(puntDir);
			memcpy(contenido, contenidoAux, (maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize) - divInicio.rem);
			free(contenidoAux);

			offsetGrabacion = (maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize) - divInicio.rem;
			punteroActual++;

			//LEO LOS DEL MEDIO
			//SI SOLO SON DOS NO VA A ENTRAR EN EL FOR
			for (; punteroActual < punteroIndFin; punteroActual++) {
				contenidoBloque = leerBloqueGlobal(puntInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
				puntDir = malloc(staticSuperBlock.blockSize);
				memcpy(puntDir, contenidoBloque, staticSuperBlock.blockSize);
				free(contenidoBloque);
				contenidoAux = leerNBloquesNivel0(blockGroup, puntDir, 0, (maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize));
				free(puntDir);
				memcpy(contenido + offsetGrabacion, contenidoAux, maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize);
				free(contenidoAux);

				offsetGrabacion += maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize;
			}

			//LEO EL DEL FINAL
			//EL PUNTERO ACTUAL ES EL PUNTERO FINAL
			contenidoBloque = leerBloqueGlobal(puntInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			puntDir = malloc(staticSuperBlock.blockSize);
			memcpy(puntDir, contenidoBloque, staticSuperBlock.blockSize);
			free(contenidoBloque);
			contenidoAux = leerNBloquesNivel0(blockGroup, puntDir, 0, offsetFinal);
			free(puntDir);
			memcpy(contenido + offsetGrabacion, contenidoAux, offsetFinal);
			free(contenidoAux);
		}
	}
	return contenido;
}

char* leerNBloquesNivel2(uint8_t blockGroup, uint32_t* puntBiInd, off_t byteOffset, size_t sizeBytes) {
	char* contenido = NULL;
	if (sizeBytes > 0) {
		uint64_t byteFin = byteOffset + sizeBytes;
		div_t divInicio = div(byteOffset, maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize);
		uint16_t punteroBiIndInicio = divInicio.quot;
		div_t divFin = div(byteFin, maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize);
		uint16_t punteroBiIndFin = divFin.quot;
		off_t offsetFinal = divFin.rem;
		if(divFin.rem == 0){
			punteroBiIndFin--;
			offsetFinal = 1024; //TODO revisar que esto sea realmente necesario
			//printf("Como el offset es 0 seteo el bloque final a [%d] y el offset a [%d].\n", punteroBiIndFin, (uint32_t) offsetFinal);
		}

		uint16_t punteroActual;
		contenido = malloc(sizeBytes);

		if (punteroBiIndInicio == punteroBiIndFin) {
			//EL PRIMERO TAMBIEN ES EL ULTIMO
			punteroActual = punteroBiIndInicio;
			char* contenidoBloque = leerBloqueGlobal(puntBiInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			uint32_t* puntBiInd = malloc(staticSuperBlock.blockSize);
			memcpy(puntBiInd, contenidoBloque, staticSuperBlock.blockSize);
			free(contenidoBloque);
			char* contenidoAux = leerNBloquesNivel1(blockGroup, puntBiInd, divInicio.rem, sizeBytes);
			free(puntBiInd);
			memcpy(contenido, contenidoAux, sizeBytes);
			free(contenidoAux);
		} else {
			//EL PRIMERO NO ES EL ULTIMO
			//LEO EL PRIMERO
			off_t offsetGrabacion = 0;
			punteroActual = punteroBiIndInicio;
			char* contenidoBloque = leerBloqueGlobal(puntBiInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			uint32_t* puntInd = malloc(staticSuperBlock.blockSize);
			memcpy(puntInd, contenidoBloque, staticSuperBlock.blockSize);
			free(contenidoBloque);
			char* contenidoAux = leerNBloquesNivel1(blockGroup, puntInd, divInicio.rem, (maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize) - divInicio.rem);
			free(puntInd);
			memcpy(contenido, contenidoAux, (maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize) - divInicio.rem);
			free(contenidoAux);

			offsetGrabacion = (maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize) - divInicio.rem;
			punteroActual++;

			//LEO LOS DEL MEDIO
			//SI SOLO SON DOS NO VA A ENTRAR EN EL FOR
			for (; punteroActual < punteroBiIndFin; punteroActual++) {
				contenidoBloque = leerBloqueGlobal(puntBiInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
				puntInd = malloc(staticSuperBlock.blockSize);
				memcpy(puntInd, contenidoBloque, staticSuperBlock.blockSize);
				free(contenidoBloque);
				contenidoAux = leerNBloquesNivel1(blockGroup, puntInd, 0, (maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize));
				free(puntInd);
				memcpy(contenido + offsetGrabacion, contenidoAux, maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize);
				free(contenidoAux);

				offsetGrabacion += maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize;
			}

			//LEO EL DEL FINAL
			//EL PUNTERO ACTUAL ES EL PUNTERO FINAL
			contenidoBloque = leerBloqueGlobal(puntBiInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			puntInd = malloc(staticSuperBlock.blockSize);
			memcpy(puntInd, contenidoBloque, staticSuperBlock.blockSize);
			free(contenidoBloque);
			contenidoAux = leerNBloquesNivel1(blockGroup, puntInd, 0, offsetFinal);
			free(puntInd);
			memcpy(contenido + offsetGrabacion, contenidoAux, offsetFinal);
			free(contenidoAux);
		}
	}
	return contenido;
}

char* leerNBloquesNivel3(uint8_t blockGroup, uint32_t* puntTriInd, off_t byteOffset, size_t sizeBytes) {
	char* contenido = NULL;
	if (sizeBytes > 0) {
		uint64_t byteFin = byteOffset + sizeBytes;
		div_t divInicio = div(byteOffset, maxCantBloquesIndirectosTriples() * staticSuperBlock.blockSize);
		uint16_t punteroTriIndInicio = divInicio.quot;
		div_t divFin = div(byteFin, maxCantBloquesIndirectosTriples() * staticSuperBlock.blockSize);
		uint16_t punteroTriIndFin = divFin.quot;
		off_t offsetFinal = divFin.rem;
		if(divFin.rem == 0){
			punteroTriIndFin--;
			offsetFinal = 1024; //TODO revisar que esto sea realmente necesario
			//printf("Como el offset es 0 seteo el bloque final a [%d] y el offset a [%d].\n", punteroTriIndFin, (uint32_t) offsetFinal);
		}

		uint16_t punteroActual;
		contenido = malloc(sizeBytes);

		if (punteroTriIndInicio == punteroTriIndFin) {
			//EL PRIMERO TAMBIEN ES EL ULTIMO
			punteroActual = punteroTriIndInicio;
			char* contenidoBloque = leerBloqueGlobal(puntTriInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			uint32_t* puntBiInd = malloc(staticSuperBlock.blockSize);
			memcpy(puntBiInd, contenidoBloque, staticSuperBlock.blockSize);
			free(contenidoBloque);
			char* contenidoAux = leerNBloquesNivel2(blockGroup, puntBiInd, divInicio.rem, sizeBytes);
			free(puntBiInd);
			memcpy(contenido, contenidoAux, sizeBytes);
			free(contenidoAux);
		} else {
			//EL PRIMERO NO ES EL ULTIMO
			//LEO EL PRIMERO
			off_t offsetGrabacion = 0;
			punteroActual = punteroTriIndInicio;
			char* contenidoBloque = leerBloqueGlobal(puntTriInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			uint32_t* puntBiInd = malloc(staticSuperBlock.blockSize);
			memcpy(puntBiInd, contenidoBloque, staticSuperBlock.blockSize);
			free(contenidoBloque);
			char* contenidoAux = leerNBloquesNivel2(blockGroup, puntBiInd, divInicio.rem, (maxCantBloquesIndirectosTriples() * staticSuperBlock.blockSize) - divInicio.rem);
			free(puntBiInd);
			memcpy(contenido, contenidoAux, (maxCantBloquesIndirectosTriples() * staticSuperBlock.blockSize) - divInicio.rem);
			free(contenidoAux);

			offsetGrabacion = (maxCantBloquesIndirectosTriples() * staticSuperBlock.blockSize) - divInicio.rem;
			punteroActual++;

			//LEO LOS DEL MEDIO
			//SI SOLO SON DOS NO VA A ENTRAR EN EL FOR
			for (; punteroActual < (punteroTriIndFin - 1); punteroActual++) {
				contenidoBloque = leerBloqueGlobal(puntTriInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
				puntBiInd = malloc(staticSuperBlock.blockSize);
				memcpy(puntBiInd, contenidoBloque, staticSuperBlock.blockSize);
				free(contenidoBloque);
				contenidoAux = leerNBloquesNivel2(blockGroup, puntBiInd, 0, (maxCantBloquesIndirectosTriples() * staticSuperBlock.blockSize));
				free(puntBiInd);
				memcpy(contenido + offsetGrabacion, contenidoAux, maxCantBloquesIndirectosTriples() * staticSuperBlock.blockSize);
				free(contenidoAux);

				offsetGrabacion += maxCantBloquesIndirectosTriples() * staticSuperBlock.blockSize;
			}

			//LEO EL DEL FINAL
			//EL PUNTERO ACTUAL ES EL PUNTERO FINAL
			contenidoBloque = leerBloqueGlobal(puntTriInd[punteroActual])/* TODO leerBloqueLocal(blockGroup, puntDir[punteroActual])*/;
			puntBiInd = malloc(staticSuperBlock.blockSize);
			memcpy(puntBiInd, contenidoBloque, staticSuperBlock.blockSize);
			free(contenidoBloque);
			contenidoAux = leerNBloquesNivel2(blockGroup, puntBiInd, 0, offsetFinal);
			free(puntBiInd);
			memcpy(contenido + offsetGrabacion, contenidoAux, offsetFinal);
			free(contenidoAux);
		}
	}
	return contenido;
}

char* leerIndireccionamiento(uint8_t blockGroup, inodeStructure_t inodo, off_t offset, size_t size) {
	//printf("Comienzo a leer los indireccionamientos.\n");
	div_t divInicio = div(offset, staticSuperBlock.blockSize);
	uint64_t bloqueInicio = divInicio.quot;
	//printf("El bloque de inicio es el [%d].\n", (uint32_t) bloqueInicio);
	div_t divFin = div(offset + size, staticSuperBlock.blockSize);
	uint64_t bloqueFin = divFin.quot;
	//printf("El bloque final es el [%d].\n", (uint32_t) bloqueFin);
	char* contenido = malloc(size);
	if (bloqueInicio < 12 && bloqueFin < 12) {
		//SOLO HAY QUE LEER LOS PUNTEROS DIRECTOS
		//printf("Solo hay que leer los punteros directos.\n");
		char* contenidoAuxDir = leerNBloquesNivel0(blockGroup, inodo.block, offset, size);
		memcpy(contenido, contenidoAuxDir, size);
		free(contenidoAuxDir);
	} else if (bloqueInicio < 12 && bloqueFin < 12 + maxCantBloquesIndirectosSimples()) {
		//HAY QUE LEER LOS PUNTEROS DIRECTOS Y EL INDIRECTO SIMPLE
		//printf("Hay que leer los punteros directos y el indirecto simple.\n");
		//printf("----------------------------------------------------------------------------------------------------\n");
		//printf("Leo los punteros directos.\n");
		char* contenidoAuxDir = leerNBloquesNivel0(blockGroup, inodo.block, offset, 12 * staticSuperBlock.blockSize - offset);
		//printf("Lei los punteros directos:\n");
		//uint32_t i;
		//for(i = 0; i < 12 * staticSuperBlock.blockSize - offset; i++){
			//printf("Byte:[%d] -- Contenido:[%d]:[%c]\n", i, contenidoAuxDir[i], contenidoAuxDir[i]);
		//}
		//printf("----------------------------------------------------------------------------------------------------\n");
		//printf("Leo el puntero indirecto.\n");
		char* contenidoAuxInd = leerNBloquesNivel1(blockGroup, inodo.block + 12, 0, (offset + size) - (12 * staticSuperBlock.blockSize));
		//printf("Lei el puntero indirecto.\n");
		//for(i = 0; i < (offset + size) - (12 * staticSuperBlock.blockSize); i++){
			//printf("Byte:[%d] -- Contenido:[%d]:[%c]\n", i, (uint32_t) contenidoAuxInd[i], (uint32_t) contenidoAuxInd[i]);
		//}
		memcpy(contenido, contenidoAuxDir, 12 * staticSuperBlock.blockSize - offset);
		uint64_t desplazamiento = 12 * staticSuperBlock.blockSize - offset;
		//printf("El desplazamiento es: [%d].\n", (uint32_t) desplazamiento);
		memcpy(contenido + desplazamiento, contenidoAuxInd, (offset + size) - (12 * staticSuperBlock.blockSize));
		free(contenidoAuxDir);
		free(contenidoAuxInd);
	} else if (bloqueInicio < 12 && bloqueFin < 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) {
		//HAY QUE LEER LOS PUNTEROS DIRECTOS, EL INDIRECTO SIMPLE Y EL INDIRECTO DOBLE
		//printf("Hay que leer los punteros directos, el indirecto simple y el indirecto doble.\n");
		//printf("----------------------------------------------------------------------------------------------------\n");
		//printf("Leo los punteros directos.\n");
		char* contenidoAuxDir = leerNBloquesNivel0(blockGroup, inodo.block, offset, 12 * staticSuperBlock.blockSize - offset);
		//printf("Lei los punteros directos:\n");
		//uint32_t i;
		//for(i = 0; i < 12 * staticSuperBlock.blockSize - offset; i++){
			//printf("Byte:[%d] -- Contenido:[%d]:[%c]\n", i, contenidoAuxDir[i], contenidoAuxDir[i]);
		//}
		//printf("----------------------------------------------------------------------------------------------------\n");
		//printf("Leo el puntero indirecto.\n");
		char* contenidoAuxInd = leerNBloquesNivel1(blockGroup, inodo.block + 12, 0, (maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize));
		//printf("Lei el puntero indirecto.\n");
		//for(i = 0; i < (maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize); i++){
			//printf("Byte:[%d] -- Contenido:[%d]:[%c]\n", i, (uint32_t) contenidoAuxInd[i], (uint32_t) contenidoAuxInd[i]);
		//}
		//printf("----------------------------------------------------------------------------------------------------\n");
		//printf("Leo el puntero doblemente indirecto.\n");
		char* contenidoAuxBiInd = leerNBloquesNivel2(blockGroup, inodo.block + 13, 0, (offset + size) - ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize));
		//printf("Lei el puntero doblemente indirecto.\n");
		//for(i = 0; i < (offset + size) - ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize); i++){
			//printf("Byte:[%d] -- Contenido:[%d]:[%c]\n", i, (uint32_t) contenidoAuxBiInd[i], (uint32_t) contenidoAuxBiInd[i]);
		//}
		memcpy(contenido, contenidoAuxDir, 12 * staticSuperBlock.blockSize - offset);
		uint64_t desplazamiento = 12 * staticSuperBlock.blockSize - offset;
		memcpy(contenido + desplazamiento, contenidoAuxInd, (maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize));
		desplazamiento += maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize;
		memcpy(contenido + desplazamiento, contenidoAuxBiInd, (offset + size) - ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize));
		free(contenidoAuxDir);
		free(contenidoAuxInd);
		free(contenidoAuxBiInd);
	} else if (bloqueInicio < 12 && bloqueFin < 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles() + maxCantBloquesIndirectosTriples()) {
		//HAY QUE LEER LOS PUNTEROS DIRECTOS, EL INDIRECTO SIMPLE, EL INDIRECTO DOBLE Y EL INDIRECTO TRIPLE
		//printf("Hay que leer los punteros directos, el indirecto simple, el indirecto doble y el indirecto triple.\n");
		char* contenidoAuxDir = leerNBloquesNivel0(blockGroup, inodo.block, offset, 12 * staticSuperBlock.blockSize - offset);
		char* contenidoAuxInd = leerNBloquesNivel1(blockGroup, inodo.block + 12, 0, (maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize));
		char* contenidoAuxBiInd = leerNBloquesNivel2(blockGroup, inodo.block + 13, 0, (maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize));
		char* contenidoAuxTriInd = leerNBloquesNivel3(blockGroup, inodo.block + 14, 0, (offset + size) - ((12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) * staticSuperBlock.blockSize));
		memcpy(contenido, contenidoAuxDir, 12 * staticSuperBlock.blockSize - offset);
		uint64_t desplazamiento = 12 * staticSuperBlock.blockSize - offset;
		memcpy(contenido + desplazamiento, contenidoAuxInd, (maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize));
		desplazamiento += maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize;
		memcpy(contenido + desplazamiento, contenidoAuxBiInd, (maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize));
		desplazamiento += maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize;
		memcpy(contenido + desplazamiento, contenidoAuxTriInd, (offset + size) - ((12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) * staticSuperBlock.blockSize));
		free(contenidoAuxDir);
		free(contenidoAuxInd);
		free(contenidoAuxBiInd);
		free(contenidoAuxTriInd);
	} else if (bloqueInicio > 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles() && bloqueFin > 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) {
		//SOLO HAY QUE LEER EL PUNTERO INDIRECTO TRIPLE
		//printf("Solo hay que leer el puntero indirecto triple.\n");
		char* contenidoAuxTriInd = leerNBloquesNivel3(blockGroup, inodo.block + 14, offset - ((12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) * staticSuperBlock.blockSize), size);
		memcpy(contenido, contenidoAuxTriInd, size);
		free(contenidoAuxTriInd);
	} else if (bloqueInicio > 12 + maxCantBloquesIndirectosSimples() && bloqueFin > 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) {
		//HAY QUE LEER EL PUNTERO INDIRECTO DOBLE Y EL INDIRECTO TRIPLE
		//printf("Hay que leer  el indirecto doble y el indirecto triple.\n");
		char* contenidoAuxBiInd = leerNBloquesNivel2(blockGroup, inodo.block + 13, offset - ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize), ((12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) * staticSuperBlock.blockSize) - offset);
		char* contenidoAuxTriInd = leerNBloquesNivel3(blockGroup, inodo.block + 14, 0, (offset + size) - ((12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) * staticSuperBlock.blockSize));
		memcpy(contenido, contenidoAuxBiInd, ((12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) * staticSuperBlock.blockSize) - offset);
		uint64_t desplazamiento = ((12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) * staticSuperBlock.blockSize) - offset;
		memcpy(contenido + desplazamiento, contenidoAuxTriInd, (offset + size) - ((12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) * staticSuperBlock.blockSize));
		free(contenidoAuxBiInd);
		free(contenidoAuxTriInd);
	} else if (bloqueInicio > 12 && bloqueFin > 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) {
		//HAY QUE LEER EL PUNTERO INDIRECTO SIMPLE, EL INDIRECTO DOBLE Y EL INDIRECTO TRIPLE
		//printf("Hay que leer  el indirecto simple, el indirecto doble y el indirecto triple.\n");
		char* contenidoAuxInd = leerNBloquesNivel1(blockGroup, inodo.block + 12, offset - (12 * staticSuperBlock.blockSize), ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize) - offset);
		char* contenidoAuxBiInd = leerNBloquesNivel2(blockGroup, inodo.block + 13, 0, (maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize));
		char* contenidoAuxTriInd = leerNBloquesNivel3(blockGroup, inodo.block + 14, 0, (offset + size) - ((12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) * staticSuperBlock.blockSize));
		memcpy(contenido, contenidoAuxInd, ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize) - offset);
		uint64_t desplazamiento = ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize) - offset;
		memcpy(contenido + desplazamiento, contenidoAuxBiInd, (maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize));
		desplazamiento += maxCantBloquesIndirectosDobles() * staticSuperBlock.blockSize;
		memcpy(contenido + desplazamiento, contenidoAuxTriInd, (offset + size) - ((12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) * staticSuperBlock.blockSize));
		free(contenidoAuxInd);
		free(contenidoAuxBiInd);
	} else if ((bloqueInicio > 12 && bloqueInicio < 12 + maxCantBloquesIndirectosSimples()) && (bloqueFin > 12 + maxCantBloquesIndirectosSimples() && bloqueFin < 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles())) {
		//HAY QUE LEER EL PUNTERO INDIRECTO SIMPLE Y EL INDIRECTO DOBLE
		//printf("Hay que leer  el indirecto simple y el indirecto doble.\n");
		char* contenidoAuxInd = leerNBloquesNivel1(blockGroup, inodo.block + 12, offset - (12 * staticSuperBlock.blockSize), ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize) - offset);
		char* contenidoAuxBiInd = leerNBloquesNivel2(blockGroup, inodo.block + 13, 0, (offset + size) - ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize));
		memcpy(contenido, contenidoAuxInd, (maxCantBloquesIndirectosSimples() * staticSuperBlock.blockSize));
		uint64_t desplazamiento = ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize) - offset;
		memcpy(contenido + desplazamiento, contenidoAuxBiInd, (offset + size) - ((12 + maxCantBloquesIndirectosSimples()) * staticSuperBlock.blockSize));
		free(contenidoAuxInd);
		free(contenidoAuxBiInd);
	}
	return contenido;
}

//----------------------------------------------------------------------------------------------------
//OBTENER UN INODO A PARTIR DE UN PATH
//----------------------------------------------------------------------------------------------------

/*uint8_t buscarEnDirBloque(uint8_t* blockGroup, char* bloque, uint64_t cantBytes, char* nombre, inodeStructure_t* inodoBuscado) {
	uint8_t encontrado = 0;
	uint64_t i;
	for (i = 0; i < cantBytes && !encontrado;) {
		uint64_t iAux = i;
		if ((iAux + 4) < cantBytes) {
			uint32_t numInodo;
			memcpy(&numInodo, bloque + i, 4);
			iAux += 4;
			if ((iAux + 2) < cantBytes) {
				uint16_t longRegistro;
				if(longRegistro > 0){
					memcpy(&longRegistro, bloque + iAux, 2);
					iAux += 2;
					if ((iAux + 1) < cantBytes) {
						uint8_t longNombre;
						memcpy(&longNombre, bloque + iAux, 1);
						iAux += 1;
						if ((iAux + longNombre) < cantBytes) {
							char* nombreAux = malloc(longNombre + 1);
							memset(nombreAux, '\0', longNombre + 1);
							memcpy(nombreAux, bloque + iAux, longNombre);
							iAux += longNombre;
							if (strcmp(nombreAux, nombre) == 0) {
								encontrado = 1;
								//TODO revisasr
								*blockGroup = numInodo / staticSuperBlock.inodesPerGroup;
								//TODO SE PUEDE OPTIMIZAR EVITANDO LEER LA INODE TABLE COMPLETA
								inodeStructure_t* inodeTable = leerInodeTable(*blockGroup);
								memcpy(inodoBuscado, &(inodeTable[numInodo % staticSuperBlock.inodesPerGroup]), sizeof(inodeStructure_t));
							}
							div_t division = div(longRegistro, 4);
							i += division.quot * 4;
							if (division.rem != 0) {
								i++;
							}
						}
					}
				}else{
					i+=4;
				}
			}
		}
	}
	return encontrado;
}*/

/*uint8_t buscarEnDirNivel0(uint8_t *blockGroup, uint32_t* bloques, uint64_t maxCantBloques, char* nombre, inodeStructure_t* inodoBuscado) {
	uint8_t encontrado = 0;
	uint32_t i;
	for (i = 0; !encontrado && i < maxCantBloques && !encontrado; i++) {
		char* buffer = leerBloqueLocal(*blockGroup, bloques[i]);
		uint32_t tamanioBloque = staticSuperBlock.blockSize;
		char* bloquesAux = (char*) malloc(tamanioBloque);
		memset(bloquesAux, 0, tamanioBloque);
		memcpy(bloquesAux, buffer, tamanioBloque);
		encontrado = buscarEnDirBloque(blockGroup, bloquesAux, tamanioBloque, nombre, inodoBuscado);
		free(bloquesAux);
	}
	return encontrado;
}*/

/*uint8_t buscarEnDirNivel1(uint8_t *blockGroup, uint32_t* bloques, uint64_t maxCantBloques, char* nombre, inodeStructure_t* inodoBuscado) {
	//TODO REVISAR ESTA DIVISION
	div_t division = div(maxCantBloques, maxCantBloquesIndirectosSimples());
	uint64_t cantPunteros = division.quot;
	if (division.rem != 0) {
		cantPunteros++;
	}
	uint8_t encontrado = 0;
	uint32_t i;
	for (i = 0; !encontrado && i < cantPunteros && !encontrado; i++) {
		char* buffer = leerBloqueLocal(*blockGroup, bloques[i]);
		uint32_t tamanioBloque = staticSuperBlock.blockSize;
		uint32_t* bloquesAux = (uint32_t*) malloc(tamanioBloque);
		memset(bloquesAux, 0, tamanioBloque);
		memcpy(bloquesAux, buffer, tamanioBloque);
		encontrado = buscarEnDirNivel0(blockGroup, bloquesAux, tamanioBloque / sizeof(uint32_t), nombre, inodoBuscado);
		free(bloquesAux);
	}
	return encontrado;
}*/

/*uint8_t buscarEnDirNivel2(uint8_t *blockGroup, uint32_t* bloques, uint64_t maxCantBloques, char* nombre, inodeStructure_t* inodoBuscado) {
	//TODO REVISAR ESTA DIVISION
	div_t division = div(maxCantBloques, maxCantBloquesIndirectosDobles());
	uint64_t cantPunteros = division.quot;
	if (division.rem != 0) {
		cantPunteros++;
	}
	uint8_t encontrado = 0;
	uint32_t i;
	for (i = 0; !encontrado && i < cantPunteros && !encontrado; i++) {
		char* buffer = leerBloqueLocal(*blockGroup, bloques[i]);
		uint32_t tamanioBloque = staticSuperBlock.blockSize;
		uint32_t* bloquesAux = (uint32_t*) malloc(tamanioBloque);
		memset(bloquesAux, 0, tamanioBloque);
		memcpy(bloquesAux, buffer, tamanioBloque);
		encontrado = buscarEnDirNivel1(blockGroup, bloquesAux, tamanioBloque / sizeof(uint32_t), nombre, inodoBuscado);
		free(bloquesAux);
	}
	return encontrado;
}*/

/*uint8_t buscarEnDirNivel3(uint8_t *blockGroup, uint32_t* bloques, uint64_t maxCantBloques, char* nombre, inodeStructure_t* inodoBuscado) {
	//TODO REVISAR ESTA DIVISION
	div_t division = div(maxCantBloques, maxCantBloquesIndirectosTriples());
	uint64_t cantPunteros = division.quot;
	if (division.rem != 0) {
		cantPunteros++;
	}
	uint8_t encontrado = 0;
	uint32_t i;
	for (i = 0; !encontrado && i < cantPunteros && !encontrado; i++) {
		char* buffer = leerBloqueLocal(*blockGroup, bloques[i]);
		uint32_t tamanioBloque = staticSuperBlock.blockSize;
		uint32_t* bloquesAux = (uint32_t*) malloc(tamanioBloque);
		memset(bloquesAux, 0, tamanioBloque);
		memcpy(bloquesAux, buffer, tamanioBloque);
		encontrado = buscarEnDirNivel2(blockGroup, bloquesAux, tamanioBloque / sizeof(uint32_t), nombre, inodoBuscado);
		free(bloquesAux);
	}
	return encontrado;
}*/

uint8_t buscarEnDir(uint8_t *numBlockGroup, inodeStructure_t inodoDir, char* nombre, inodeStructure_t* inodoBuscado, uint32_t* numInodo) {
	//TODO revisar
	/*uint8_t encontrado = 0;
	 uint32_t* bloques = (uint32_t*) malloc(12 * sizeof(uint32_t));
	 memcpy(bloques, inodoDir.block, 12 * sizeof(uint32_t));
	 uint64_t cantPunteros;
	 if (inodoDir.blocks < 12) {
	 cantPunteros = inodoDir.blocks;
	 } else {
	 cantPunteros = 12;
	 }
	 encontrado = buscarEnDirNivel0(blockGroup, bloques, cantPunteros, nombre, inodoBuscado);
	 free(bloques);
	 if (!encontrado && inodoDir.blocks > 12) {
	 if (inodoDir.blocks < (12 + maxCantBloquesIndirectosSimples())) {
	 cantPunteros = inodoDir.blocks - 12;
	 } else {
	 cantPunteros = maxCantBloquesIndirectosSimples();
	 }
	 bloques = (uint32_t*) malloc(sizeof(uint32_t));
	 memcpy(bloques, inodoDir.block + 12, sizeof(uint32_t));
	 encontrado = buscarEnDirNivel1(blockGroup, bloques, cantPunteros, nombre, inodoBuscado);
	 free(bloques);
	 if (!encontrado && inodoDir.blocks > (12 + maxCantBloquesIndirectosSimples())) {
	 if (inodoDir.blocks < (12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles())) {
	 cantPunteros = inodoDir.blocks - 12 - maxCantBloquesIndirectosSimples();
	 } else {
	 cantPunteros = maxCantBloquesIndirectosDobles();
	 }
	 bloques = (uint32_t*) malloc(sizeof(uint32_t));
	 memcpy(bloques, inodoDir.block + 13, sizeof(uint32_t));
	 encontrado = buscarEnDirNivel2(blockGroup, bloques, cantPunteros, nombre, inodoBuscado);
	 free(bloques);
	 if (!encontrado && inodoDir.blocks > (12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles())) {
	 if (inodoDir.blocks < (12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles() + maxCantBloquesIndirectosTriples())) {
	 cantPunteros = inodoDir.blocks - 12 - maxCantBloquesIndirectosSimples() - maxCantBloquesIndirectosDobles();
	 } else {
	 cantPunteros = maxCantBloquesIndirectosTriples();
	 }
	 bloques = (uint32_t*) malloc(sizeof(uint32_t));
	 memcpy(bloques, inodoDir.block + 14, sizeof(uint32_t));
	 encontrado = buscarEnDirNivel3(blockGroup, bloques, cantPunteros, nombre, inodoBuscado);
	 free(bloques);
	 }
	 }
	 }
	 return encontrado;*/
	char* contenidoDirectorio = leerIndireccionamiento(*numBlockGroup, inodoDir, 0, inodoDir.size);
	uint64_t i;
	uint8_t encontrado = 0;
	for (i = 0; i < inodoDir.size && !encontrado;) {
		uint64_t iAux = i;
		if ((iAux + 4) < inodoDir.size) {
			memcpy(numInodo, contenidoDirectorio + i, 4);
			printf("Numero de Inodo: [%d].\n", *numInodo);
			(*numInodo)--; //para que el primer inodo sea el 0 y no el 1
			iAux += 4;
			if ((iAux + 2) < inodoDir.size) {
				uint16_t longRegistro;
				if(longRegistro > 0){
					memcpy(&longRegistro, contenidoDirectorio + iAux, 2);
					printf("-Longitud del Registro: [%d].\n", longRegistro);
					iAux += 2;
					if ((iAux + 1) < inodoDir.size) {
						uint8_t longNombre;
						memcpy(&longNombre, contenidoDirectorio + iAux, 1);
						printf("--Longitud del Nombre: [%d].\n", longNombre);
						iAux += 1;
						if ((iAux + 1) < inodoDir.size) {
							uint8_t modo;
							memcpy(&modo, contenidoDirectorio + iAux, 1);
							printf("---Modo: [%d].\n", modo);
							iAux += 1;
							if ((iAux + longNombre) < inodoDir.size) {
								char* nombreAux = malloc(longNombre + 1);
								memset(nombreAux, '\0', longNombre + 1);
								memcpy(nombreAux, contenidoDirectorio + iAux, longNombre);
								printf("----Nombre: [%s].\n", nombreAux);
								if (strcmp(nombreAux, nombre) == 0) {
									printf("-----Lo encontre!!!.\n");
									encontrado = 1;
									*numBlockGroup = *numInodo / staticSuperBlock.inodesPerGroup;
									//TODO SE PUEDE OPTIMIZAR EVITANDO LEER LA INODE TABLE COMPLETA
									inodeStructure_t* inodeTable = leerInodeTable(*numBlockGroup);
									memcpy(inodoBuscado, &(inodeTable[(*numInodo % staticSuperBlock.inodesPerGroup)]), sizeof(inodeStructure_t));
									free(inodeTable);
								}
								iAux += longNombre;
								div_t division = div(longRegistro, 4);
								i += division.quot * 4;
								if (division.rem != 0) {
									i++;
								}
							}
						}
					}
				}else{
					i+=4;
				}
			}
		}
	}
	return encontrado;
}

inodeStructure_t inodoDirectorioRaiz() {
	//TODO revisar
	inodeStructure_t inodo;
	inodeStructure_t* inodeTablePrimerBlockGroup = leerInodeTable(0);
	memcpy(&inodo, &(inodeTablePrimerBlockGroup[1]), sizeof(inodeStructure_t));
	free(inodeTablePrimerBlockGroup);
	return inodo;
}

uint8_t obtenerInodoPath(char* path, inodeStructure_t* inodoBuscado, uint8_t* numBlockGroup, uint32_t* numInodo) {
	//TODO REVISAR
	nodoNombreDirOArch_t* colaPathFte = NULL;
	nodoNombreDirOArch_t* colaPathFin = NULL;
	parsearPath(path, &colaPathFte, &colaPathFin);

	inodeStructure_t inodoAux = inodoDirectorioRaiz();
	*numInodo = 1;
	uint8_t blockGroupActual = 0;
	uint8_t encontrado;
	if (colaPathFte == NULL) {
		//ES EL DIRECTORIO RAIZ
		printf("Es el directorio raiz.\n");
		imprimirContenidoInodo(inodoAux);
		encontrado = 1;
	} else {
		encontrado = 1;
		while (encontrado && colaPathFte != NULL) {
			char* nombre = NULL;
			desencolarNombreDirOArch(&colaPathFte, &colaPathFin, &nombre);
			printf("Ahora busco el nombre: [%s].\n", nombre);
			encontrado = buscarEnDir(&blockGroupActual, inodoAux, nombre, &inodoAux, numInodo);
			printf("Encontre el inodo:\n");
			imprimirContenidoInodo(inodoAux);
			free(nombre);
		}
	}
	if (encontrado) {
		*inodoBuscado = inodoAux;
		*numBlockGroup = blockGroupActual;
		return 0;
	} else {
		return -ENOENT;
	}
}

//----------------------------------------------------------------------------------------------------
//LECTURA DE UN DIRECTORIO
//----------------------------------------------------------------------------------------------------

nodoNombreDirOArch_t* parsearDirectorio(char* contenidoDirectorio, size_t size) {
	nodoNombreDirOArch_t* colaNombresFte = NULL;
	nodoNombreDirOArch_t* colaNombresFin = NULL;
	uint64_t i;
	uint32_t cantElementos = 0;
	for (i = 0; i < size;) {
		uint64_t iAux = i;
		if ((iAux + 4) < size) {
			uint32_t numInodo;
			memcpy(&numInodo, contenidoDirectorio + i, 4);
			printf("Elemento [%d].\n", cantElementos);
			cantElementos++;
			printf("Numero de Inodo: [%d].\n", numInodo);
			iAux += 4;
			if ((iAux + 2) < size) {
				uint16_t longRegistro;
				if(longRegistro > 0){
				memcpy(&longRegistro, contenidoDirectorio + iAux, 2);
				printf("-Longitud del Registro: [%d].\n", longRegistro);
				iAux += 2;
				if ((iAux + 1) < size) {
					uint8_t longNombre;
					memcpy(&longNombre, contenidoDirectorio + iAux, 1);
					printf("--Longitud del Nombre: [%d].\n", longNombre);
					iAux += 1;
					if ((iAux + 1) < size) {
						uint8_t modo;
						memcpy(&modo, contenidoDirectorio + iAux, 1);
						printf("---Modo: [%d].\n", modo);
						iAux += 1;
						if ((iAux + longNombre) < size) {
							char* nombreAux = malloc(longNombre + 1);
							memset(nombreAux, '\0', longNombre + 1);
							memcpy(nombreAux, contenidoDirectorio + iAux, longNombre);
							printf("----Nombre: [%s].\n", nombreAux);
							iAux += longNombre;
							encolarNombreDirOArch(&colaNombresFte, &colaNombresFin, nombreAux);
							div_t division = div(longRegistro, 4);
							i += division.quot * 4;
							if (division.rem != 0) {
								i++;
							}
						}
					}
				}
			}else{
				i+=4 ;
			}
			}
		}
	}
	return colaNombresFte;
}

nodoNombreDirOArch_t* leerDirectorio(char* path, off_t offset) {
	inodeStructure_t inodoDir;
	uint8_t numBlockGroup;
	uint32_t numInodo;
	//printf("Obtengo el inodo del directorio.\n");
	uint8_t error = obtenerInodoPath(path, &inodoDir, &numBlockGroup, &numInodo);
	if (!error) {
		//printf("Voy a leer el directorio.\n");
		char* contenidoDirectorio = leerIndireccionamiento(numBlockGroup, inodoDir, offset, (inodoDir.size - offset));
		nodoNombreDirOArch_t* nombresFte = parsearDirectorio(contenidoDirectorio, inodoDir.size - offset);
		return nombresFte;
	} else {
		return NULL;
	}
}

//----------------------------------------------------------------------------------------------------
//CREACION DE UN DIRECTORIO
//----------------------------------------------------------------------------------------------------

int32_t agregarItemADirectorio(char* pathDir, char* nombreItem, mode_t modo){
	//TODO
	//obtener el inodo del directorio dentro del que se quiere crear el item
	//leerlo completo
	//buscar un espacio libre
	//si no hay espacio truncarlo a un bloque mas
	//buscar un inodo libre y un bloque libre
	//escribir los datos en un inodo y guardarlo
	//escribir los datos en el directorio y guardarlo
	return 0/*reemplazar por lo que haya que devolver*/;
}

int32_t crearDirectorio(char* path, mode_t modo){
	//TODO
	//parsear el path para obtener el path del directorio en el que se quiere crear el directorio
	return 0 /*reemplazar por agregarItemADirectorio(pathDir, nombreDirectorio, modo)*/;
}

//----------------------------------------------------------------------------------------------------
//BORRADO DE UN DIRECTORIO
//----------------------------------------------------------------------------------------------------

int32_t borrarDirectorio(char* path){
	//TODO
	//chequear que el directorio este vacio
	//liberar el inodo
	//eliminarlo del directorio al que pertenece
	return 0/*reemplazar por lo que haya que devolver*/;
}

//----------------------------------------------------------------------------------------------------
//CREACION DE UN ARCHIVO
//----------------------------------------------------------------------------------------------------

int32_t crearArchivo(char* path, mode_t modo){
	//TODO
	char* pathDeDirectorio = obtenerPathDeDirectorio(path);
	inodeStructure_t inodoBuscado;
	uint8_t numeroDeGrupoDeBloques;
	uint32_t numeroDeInodo;
	printf("obtener Inodo Path \n");
	if(obtenerInodoPath(pathDeDirectorio, &inodoBuscado, &numeroDeGrupoDeBloques, &numeroDeInodo) == 0){
		printf("inodo encontrado \n");
		int64_t bloqueDondeCree = buscarYOcuparInodoLibre(numeroDeGrupoDeBloques, 0);
		if(bloqueDondeCree != -1){
			return 0;
		}

	}
		return -ENOENT;
}

//----------------------------------------------------------------------------------------------------
//APERTURA DE UN ARCHIVO
//----------------------------------------------------------------------------------------------------

int32_t abrirArchivo(char* path) {
	//TODO
	inodeStructure_t inodoArch;
	uint8_t numBlockGroup;
	uint32_t numInodo;
	uint8_t error = obtenerInodoPath(path, &inodoArch, &numBlockGroup, &numInodo);
	if(!error){
	return 0/*reemplazar por lo que haya que devolver*/;
	}else{
		return -ENOENT;
	}
}

//----------------------------------------------------------------------------------------------------
//LECTURA DE UN ARCHIVO
//----------------------------------------------------------------------------------------------------

char* leerArchivo(char* path, off_t offset, size_t size) {
	inodeStructure_t inodoArch;
	uint8_t numBlockGroup;
	uint32_t numInodo;
	//printf("Obtengo el inodo del archivo.\n");
	uint8_t error = obtenerInodoPath(path, &inodoArch, &numBlockGroup, &numInodo);
	if (!error) {
		//printf("Voy a leer el archivo.\n");
		char* contenidoArchivo = leerIndireccionamiento(numBlockGroup, inodoArch, offset, size);
		return contenidoArchivo;
	} else {
		return NULL;
	}
}

//----------------------------------------------------------------------------------------------------
//ESCRITURA DE UN ARCHIVO
//----------------------------------------------------------------------------------------------------

int32_t escribirArchivo(char* path, size_t size, off_t offset, char* buffer){
	//TODO
	inodeStructure_t inodo;
	uint8_t numBlockGroup;
	uint32_t numInodo;
	uint8_t error = obtenerInodoPath(path, &inodo, &numBlockGroup, &numInodo);
	if(!error){
		if(size + offset > inodo.size){
			//hay que truncar el archivo
		}
		//se redondea el size para abajo y el offset para arriba para leer bloques completos
		//se leen los bloques completos (solo los que haya que escribir)
		//se pisa la informacion a escribir
		//se escriben los bloques necesarios
		return 0/*reemplazar por lo que haya que devolver*/;
	}else{
		return -ENOENT;
	}
}

//----------------------------------------------------------------------------------------------------
//BORRADO DE UN ARCHIVO
//----------------------------------------------------------------------------------------------------

int32_t borrarArchivo(char* path){
	//TODO
	truncarArchivo(path,0);
	inodeStructure_t inodoBuscado;
	uint8_t numeroDeGrupoDeBloque;
	uint32_t numeroDeInodo;
	if(obtenerInodoPath(path, &inodoBuscado, &numeroDeGrupoDeBloque, &numeroDeInodo) == 0){
		liberarInodoOcupado(numeroDeGrupoDeBloque, numeroDeInodo, 0);
		printf("archivo borrado\n");
		return 0;
	}

	printf("el archivo no se encuentra\n");
	return -ENOENT;
}

//----------------------------------------------------------------------------------------------------
//CIERRE DE UN ARCHIVO
//----------------------------------------------------------------------------------------------------

int32_t cerrarArchivo(char* path) {
	//TODO
	inodeStructure_t inodoArch;
	uint8_t numBlockGroup;
	uint32_t numInodo;
	uint8_t error = obtenerInodoPath(path, &inodoArch, &numBlockGroup, &numInodo);
	if(!error){
	return 0/*reemplazar por lo que haya que devolver*/;
	}else{
		return -ENOENT;
	}
}

//----------------------------------------------------------------------------------------------------
//TRUNCAR UN ARCHIVO
//----------------------------------------------------------------------------------------------------

uint32_t cantBloquesLibresNecesariosNivel0(uint64_t sizeViejo, uint64_t sizeNuevo){
	return 0;
}

uint32_t cantBloquesLibresNecesariosNivel1(uint64_t sizeViejo, uint64_t sizeNuevo){
	return 0;
}

uint32_t cantBloquesLibresNecesariosNivel2(uint64_t sizeViejo, uint64_t sizeNuevo){
	return 0;
}

uint32_t cantBloquesLibresNecesariosNivel3(sizeViejo, sizeNuevo){
	/*div_t divInicio = div(sizeViejo, staticSuperBlock.blockSize);
	uint64_t bloqueInicio = divInicio.quot + 1; //el divInicio.quot es el ultimo ocupado, al sumar + 1 busco el primero a ocupar
	if(divInicio.rem == 0){
		bloqueInicio--; //ej 1024 daria bloque 1 y resto 0, pero deberia dar bloque 0 y resto 1024
	}
	div_t divFin = div(sizeNuevo, staticSuperBlock.blockSize);
	uint64_t bloqueFin = divFin.quot;
	if(divFin.rem == 0){
		bloqueFin--;
	}*/
	return 0;
}

uint32_t cantBloquesLibresNecesarios(uint64_t sizeViejo, uint64_t sizeNuevo){
	/*div_t divInicio = div(sizeViejo, staticSuperBlock.blockSize);
	uint64_t bloqueInicio = divInicio.quot + 1; //el divInicio.quot es el ultimo ocupado, al sumar + 1 busco el primero a ocupar
	if(divInicio.rem == 0){
		bloqueInicio--; //ej 1024 daria bloque 1 y resto 0, pero deberia dar bloque 0 y resto 1024
	}
	div_t divFin = div(sizeNuevo, staticSuperBlock.blockSize);
	uint64_t bloqueFin = divFin.quot;
	if(divFin.rem == 0){
		bloqueFin--;
	}
	uint32_t cantBloquesALiberar = bloqueFin - bloqueInicio + 1;
	if (bloqueInicio < 12 && bloqueFin < 12) {
			//SOLO SE LIBERAN BLOQUES DIRECCIONADOS DIRECTAMENTE
			return (cantBloquesALiberar);
		} else if (bloqueInicio < 12 && bloqueFin < 12 + maxCantBloquesIndirectosSimples()) {
			//HAY QUE LIBERAR UNO MAS PARA EL BLOQUE DE DIRECCIONAMIENTOS INDIRECTOS SIMPLES
			return (cantBloquesALiberar + 1);
		} else if (bloqueInicio < 12 && bloqueFin < 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) {
			//HAY QUE LIBERAR DOS BLOQUES MAS, UNO MAS PARA EL BLOQUE DE DIRECCIONAMIENTOS INDIRECTOS SIMPLES Y OTRO PARA EL BLOQUE DE DIRECCIONAMIENTOS INDIRECTOS DOBLES
			return (cantBloquesALiberar + 2);
		} else if (bloqueInicio < 12 && bloqueFin < 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles() + maxCantBloquesIndirectosTriples()) {
			//HAY QUE LIBERAR TRES BLOQUES MAS, UNO MAS PARA EL BLOQUE DE DIRECCIONAMIENTOS INDIRECTOS SIMPLES, OTRO PARA EL BLOQUE DE DIRECCIONAMIENTOS INDIRECTOS DOBLES Y OTRO PARA EL BLOQUE DE DIRECCIONAMIENTOS INDIRECTOS TRIPLES
			return (cantBloquesALiberar + 3);
		} else if (bloqueInicio > 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles() && bloqueFin > 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) {
			//SOLO SE LIBERAN BLOQUES DIRECCIONADOS DIRECTAMENTE DENTRO DEL

		} else if (bloqueInicio > 12 + maxCantBloquesIndirectosSimples() && bloqueFin > 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) {
			//HAY QUE LEER EL PUNTERO INDIRECTO DOBLE Y EL INDIRECTO TRIPLE

		} else if (bloqueInicio > 12 && bloqueFin > 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles()) {
			//HAY QUE LEER EL PUNTERO INDIRECTO SIMPLE, EL INDIRECTO DOBLE Y EL INDIRECTO TRIPLE

		} else if ((bloqueInicio > 12 && bloqueInicio < 12 + maxCantBloquesIndirectosSimples()) && (bloqueFin > 12 + maxCantBloquesIndirectosSimples() && bloqueFin < 12 + maxCantBloquesIndirectosSimples() + maxCantBloquesIndirectosDobles())) {
			//HAY QUE LEER EL PUNTERO INDIRECTO SIMPLE Y EL INDIRECTO DOBLE

		}*/
	return 0;
}

int32_t truncarArchivo(char* path, size_t size){
	//TODO
	inodeStructure_t inodo;
	uint8_t numBlockGroup;
	uint32_t numInodo;
	uint8_t error = obtenerInodoPath(path, &inodo, &numBlockGroup, &numInodo);
	if(!error){
		uint32_t sizeViejo = inodo.size;
		uint32_t sizeNuevo = size;
		div_t division = div(sizeViejo, staticSuperBlock.blockSize);
		uint32_t cantBloquesViejos = division.quot;
		if(division.rem != 0){
			cantBloquesViejos++;
		}
		division = div(sizeNuevo, staticSuperBlock.blockSize);
		uint32_t cantBloquesNuevos = division.quot;
		if(division.rem != 0){
			cantBloquesNuevos++;
		}
		if(size < inodo.size){
			//tengo que agregar tamanio
			//me fijo si tengo que agregar bloques
			if(cantBloquesViejos != cantBloquesNuevos){
				//tengo que agregar bloques
				//busco la cantidad de bloques libres necesarios
				uint32_t* punterosBloques = buscarYOcuparNBloquesLibres(numBlockGroup, cantBloquesLibresNecesarios(sizeViejo, sizeNuevo));
				if(punterosBloques != NULL){
				//actualizo los bloques del inodo
				//TODO
				}else{
					error = 1;
				}
			}
			//escribo el archivo desde el size viejo hasta el fin con \0
			off_t sizeAEscribir = sizeNuevo - sizeViejo;
			char* info = (char*) malloc(sizeAEscribir);
			memset(info, '\0', sizeAEscribir);
			escribirArchivo(path, sizeAEscribir, sizeViejo, info);
			free(info);
		}else if(size > inodo.size){
			/*//tengo que sacar tamanio
			//me fijo si tengo que liberar bloques
			if(cantBloquesViejos != cantBloquesNuevos){
				//tengo que liberar bloques
				uint32_t* punterosBloques;
				//TODO cargar la estructura con los numeros de bloques a liberar e ir actualizando el inodo
				//libero la cantidad de bloques necesaria
				error = liberarNBloquesOcupados(uint32_t* punterosBloques);
			}*/
		}
		if(!error){
			//actualizo la estructura del inodo y la escribo
			inodo.size = size;
			division = div(inodo.size, 512);
			uint32_t cantBlocks512 = division.quot;
			if(division.rem != 0){
				cantBlocks512++;
			}
			inodo.blocks = cantBlocks512;
			escribirInodo(inodo, numInodo);
			return 0/*reemplazar por lo que haya que devolver*/;
		}else{
			//NO HAY SUFICIENTE ESPACIO EN EL DISCO
			return -1; //TODO BUSCAR UN MEJOR NUMERO DE ERROR
		}
	}else{
		return -ENOENT;
	}
}

//----------------------------------------------------------------------------------------------------
//OBTENER ATRIBUTOS
//----------------------------------------------------------------------------------------------------

int32_t obtenerAtributos(char* path, attrDirArch_t *attr) {
	inodeStructure_t inodo;
	uint8_t numBlockGroup;
	uint32_t numInodo;
	uint8_t error = obtenerInodoPath(path, &inodo, &numBlockGroup, &numInodo);
	if (!error) {
		attr->modo = inodo.mode;
		attr->size = inodo.size;
		return 0;
	} else {
		return -ENOENT;
	}
}

char* leerGrupoDeBloques(uint64_t numGroup, uint32_t blockPerGroup, uint32_t blockSize, FILE* particion) {
	char* contenido = malloc(blockPerGroup * blockSize);
	fseek(particion, 1024 + (numGroup * blockPerGroup * blockSize), SEEK_SET);
	memcpy(&contenido, particion, blockPerGroup * blockSize);
	return contenido;
}

uint16_t esGrupoConSuperBloque(uint64_t numeroDeGrupo) {
	if ((numeroDeGrupo == 0) || (numeroDeGrupo == 1) || (esPotencia(numeroDeGrupo, 3)) || esPotencia(numeroDeGrupo, 5) || esPotencia(numeroDeGrupo, 7))
		return 1;
	else
		return 0;
}

void finalizarExtended2(void) {
	if (staticGroupDescriptorTable != NULL) {
		free(staticGroupDescriptorTable);
		staticGroupDescriptorTable = NULL;
	}
}
